import { Container } from './hostConfig';
import {
	unstable_ImmediatePriority,
	unstable_NormalPriority,
	unstable_runWithPriority,
	unstable_UserBlockingPriority
} from 'scheduler';
import { Props } from 'shared/ReactTypes';

export const elementPropsKey = '__props';
const validEventTypeList = ['click'];

type EventCallback = (e: Event) => void;

interface SyntheticEvent extends Event {
	__stopPropagation: boolean;
}

interface Paths {
	capture: EventCallback[];
	bubble: EventCallback[];
}

export interface DOMElement extends Element {
	[elementPropsKey]: Props;
}

// dom[xxx] = reactElemnt props
export function updateFiberProps(elementDom: DOMElement, props: Props) {
	elementDom[elementPropsKey] = props;
}

export function initEvent(container: Container, eventType: string) {
	if (!validEventTypeList.includes(eventType)) {
		console.warn('当前不支持', eventType, '事件');
		return;
	}
	if (true) {
		console.log('初始化事件：', eventType);
	}
	container.addEventListener(eventType, (e) => {
		dispatchEvent(container, eventType, e);
	});
}

function createSyntheticEvent(e: Event) {
	const syntheticEvent = e as SyntheticEvent;
	syntheticEvent.__stopPropagation = false;
	const originStopPropagation = e.stopPropagation;

	syntheticEvent.stopPropagation = () => {
		syntheticEvent.__stopPropagation = true;
		if (originStopPropagation) {
			originStopPropagation();
		}
	};
	return syntheticEvent;
}

function dispatchEvent(container: Container, eventType: string, e: Event) {
	const targetElement = e.target;

	if (targetElement === null) {
		console.warn('事件不存在target', e);
		return;
	}

	// 1. 收集沿途的事件
	const { bubble, capture } = collectPaths(
		targetElement as DOMElement,
		container,
		eventType
	);
	// 2. 构造合成事件
	const se = createSyntheticEvent(e);

	// 3. 遍历captue
	triggerEventFlow(capture, se);

	if (!se.__stopPropagation) {
		// 4. 遍历bubble
		triggerEventFlow(bubble, se);
	}
}

function triggerEventFlow(paths: EventCallback[], se: SyntheticEvent) {
	for (let i = 0; i < paths.length; i++) {
		const callback = paths[i];

		// 该方法用于处理 设置 调度器上下文的优先级  比如 点击事件 useEffect 等
		// 事件 是用这个包裹的 当事件的回调需要执行的时候 这个函数 会根据 事件类型不同传入的优先级
		// 给全局currentPriorityLevel 设置上 当前上下文的 然后执行 对应事件的回调 事件回调里面 会进行 更新操作什么的
		// 就可以从上下文中 获取 对应的优先级 通过这个方法获取unstable_getCurrentPriorityLevel 然后把优先级 赋值给
		//  对应的更新操作 给他赋与 与事件类型相关联的优先级
		// 执行完 回调给 优先级恢复成之前的优先级
		// 源码
		// function unstable_runWithPriority(priorityLevel, eventHandler) {
		//   switch (priorityLevel) {
		//     case ImmediatePriority:
		//     case UserBlockingPriority:
		//     case NormalPriority:
		//     case LowPriority:
		//     case IdlePriority:
		//       break;
		//     default:
		//       priorityLevel = NormalPriority;
		//   }

		//   var previousPriorityLevel = currentPriorityLevel;
		//   currentPriorityLevel = priorityLevel;

		//   try {
		//     return eventHandler();
		//   } finally {
		//     currentPriorityLevel = previousPriorityLevel;
		//   }
		// }
		unstable_runWithPriority(eventTypeToSchdulerPriority(se.type), () => {
			// 回调回立刻执行 只是根据不用类型给上下文设置了不同的优先级
			// 比如 onClick = ()=>{setA()} 这个setA 就在 ImmediatePriority 优先级上下文中执行
			// setA触发更新的时候 就会将 获取 上下文中的优先级 ImmediatePriority 去交给调度器调度
			callback.call(null, se);
		});

		if (se.__stopPropagation) {
			break;
		}
	}
}

//事件 映射
function getEventCallbackNameFromEventType(
	eventType: string
): string[] | undefined {
	return {
		click: ['onClickCapture', 'onClick']
	}[eventType];
}

function collectPaths(
	targetElement: DOMElement,
	container: Container,
	eventType: string
) {
	const paths: Paths = {
		capture: [],
		bubble: []
	};

	while (targetElement && targetElement !== container) {
		// 收集
		const elementProps = targetElement[elementPropsKey];
		if (elementProps) {
			// click -> onClick onClickCapture
			const callbackNameList = getEventCallbackNameFromEventType(eventType);
			if (callbackNameList) {
				// callbackNameList = ['onClickCapture', 'onClick']
				callbackNameList.forEach((callbackName, i) => {
					//   <h1 onClick={() => {}} className="a">
					//   1
					// </h1>
					// {className: 'a', children: 1, onClick: ƒ}
					const eventCallback = elementProps[callbackName];
					if (eventCallback) {
						if (i === 0) {
							// capture
							paths.capture.unshift(eventCallback);
						} else {
							paths.bubble.push(eventCallback);
						}
					}
				});
			}
		}
		targetElement = targetElement.parentNode as DOMElement;
	}
	return paths;
}

// 根据不同的事件类型 对 事件对回调函数 设置不用对 优先级
function eventTypeToSchdulerPriority(eventType: string) {
	switch (eventType) {
		case 'click':
		case 'keydown':
		case 'keyup':
			return unstable_ImmediatePriority; //点击 键盘事件 最高优先级 同步优先级 也是宏调度 只是不可中断 为1
		case 'scroll':
			return unstable_UserBlockingPriority; // 滚动事件 拖拽等 高优先级 宏任务 可中断 为2
		default:
			return unstable_NormalPriority; // 其他的 正常优先级 为3
	}
}
